package com.lyl.module.utils;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.lyl.module.constant.ALIYUN_GLOBAL_VARIABLE;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

/**
 * @author Mr.Luo
 * @date 2022-07-21 15:05
 * @desc 阿里云盘文件工具类
 */
@Slf4j
public class AliFileUtil {


    static int errNum = 0;
    /**
     * 阿里云盘上传二进制文件
     * @param url 上传url
     * @param fileBytes 字节数组
     * @return code
     */
    public static synchronized int uploadFileBytes(String url, byte[] fileBytes){
        try {
            OkHttpClient client = new OkHttpClient().newBuilder().connectTimeout(5, TimeUnit.MINUTES).build();
            RequestBody body = RequestBody.create(null,fileBytes);
            Request request = new Request.Builder().url(url).method("PUT",body).build();
            Response response = client.newCall(request).execute();
            log.info("上传文件请求状态码：{}",response.code());
            errNum=0;
            return response.code();
        } catch (Exception e) {
            errNum++;
            log.info("上传文件遇到异常：{}",e.toString());
            if (errNum>5){
                log.info("上传文件失败次数超过：{} 次....已停止",errNum);
                return 0;
            }else{
                log.info("上传文件发起第：{} 次重试",errNum);
                uploadFileBytes(url,fileBytes);
            }
        }
        return 0;
    }

    public static String getProofCode(MultipartFile file) {
        String md5Hex = DigestUtil.md5Hex(ALIYUN_GLOBAL_VARIABLE.ACCESS_TOKEN).substring(0, 16);
        BigInteger n1 = HexUtil.toBigInteger(md5Hex);
        long n2 = file.getSize();
        long n3 = n2 == 0 ? n2 : n1.mod(BigInteger.valueOf(n2)).longValueExact();
        long min = NumberUtil.min(n3 + 8, n2);
        byte[] proofCodeBytes = readBytes(file, (int) n3, (int) min);
        return Base64.encode(proofCodeBytes);
    }

    public static String getProofCode(byte[] fileBytes) {
        String md5Hex = DigestUtil.md5Hex(ALIYUN_GLOBAL_VARIABLE.ACCESS_TOKEN).substring(0, 16);
        BigInteger n1 = HexUtil.toBigInteger(md5Hex);
        long n2 = fileBytes.length;
        long n3 = n2 == 0 ? n2 : n1.mod(BigInteger.valueOf(n2)).longValueExact();
        long min = NumberUtil.min(n3 + 8, n2);
        byte[] proofCodeBytes = Arrays.copyOfRange(fileBytes,(int)n3, (int)min);
        return Base64.encode(proofCodeBytes);
    }

    public static String getProofCode(File file) {
        String md5Hex = DigestUtil.md5Hex(ALIYUN_GLOBAL_VARIABLE.ACCESS_TOKEN).substring(0, 16);
        BigInteger n1 = HexUtil.toBigInteger(md5Hex);
        long n2 = file.length();
        long n3 = n2 == 0 ? n2 : n1.mod(BigInteger.valueOf(n2)).longValueExact();
        long min = NumberUtil.min(n3 + 8, n2);
        byte[] proofCodeBytes = readBytes(file, (int)n3, (int)min);
        return Base64.encode(proofCodeBytes);
    }

    public static byte[] readBytes(MultipartFile file, int start, int end) {
        byte[] bytes = new byte[end - start];
        try (InputStream stream = file.getInputStream()) {
            for (int i = 0; i < start; i++) {
                stream.read();
            }
            int j = 0;
            for (int i = start; i < end; i++) {
                bytes[j++] = (byte) stream.read();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
        return bytes;
    }

    public static byte[] readBytes(File file, int start, int end){
        byte[] bytes = new byte[end - start];
        try (FileInputStream stream = new FileInputStream(file)){
            for (int i = 0; i < start; i++) {
                stream.read();
            }
            int j = 0;
            for (int i = start; i < end; i++) {
                bytes[j++] = (byte) stream.read();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
        return bytes;
    }

    private static long getFileMaxPartNumber(long fileSize) {
        long max = fileSize / ALIYUN_GLOBAL_VARIABLE.DEFAULT_SIZE;
        if (max % ALIYUN_GLOBAL_VARIABLE.DEFAULT_SIZE != 0) {
            max++;
        }
        return Math.max(1,max);
    }

    /**
     * 获取 PartNumber
     *
     * @param fileSize 文件大小
     * @return jsonArray
     */
    public static JSONArray getPartNumber(long fileSize) {
        long max = getFileMaxPartNumber(fileSize);
        JSONArray array = new JSONArray();
        for (int i = 1; i <= max; i++) {
            JSONObject list = new JSONObject();
            list.set("part_number", i);
            array.add(list);
        }
        return array;
    }

}
